Portfólio

Conceitos de variáveis

Vetor

Toda variável no R é um vetor, um vetor pode visto como um conjunto de valores linear e homogêneo.

Para atribuir um valor à uma variável, utilizamos a seta <- indicando para onde estamos direcionando o valor.

É importante saber também, que para criar um vetor com valores, podemos utilizar a função c() que combina os valores em um vetor

Sendo assim, abaixo estamos criando a variável vetor e atribuindo o valor 1 5 4

vetor <- c(1, 5, 4)

vetor

Tipos de valores

Numéricos e Caracteres

No R tempos o conceito de tipos, onde cada valor tem um tipo específico, lembra das aulas de matemática sobre inteiros, decimais, etc?

Para verificar o tipo interpretado pelo R de um valor, podemos utilizar a função class(valor), onde valor é igual ao valor que você quer verificar.

class(5)
class("Olá mundo")

Reconhecendo tipos de variáveis

Veja que o R reconheceu o valor 5 como númerico e o texto “Olá mundo” como um conjunto de caracteres.

Isto também se aplica a variáveis, veja só:

variavel_numerica <- c(1,5,4,7)
variavel_caracteres <- c("Olá mundo")

class(variavel_numerica)
class(variavel_caracteres)

Também podemos usar as funções disponíveis em “is” para verificar os tipos, essa verificação retorna um tipo lógico para nós

variavel <- "5"
is.numeric(variavel)
is.character(variavel)

Lógicos

No R, também é possível criar tipos lógicos (verdadeiro ou falso)

logicos <- c(TRUE, FALSE, TRUE)
logicos2 <- c(T, F, T)

logicos
logicos2

class(logicos)

Veja que é possível abreviar as declarações.

Inteiros Explicitos

Você deve ter percebido que no caso do tipo numérico, o tipo não foi declarado explicitamente como inteiro, para fazer isso veja o próximo trecho:

inteiros <- c(1L, 2L, 3L)

inteiros
class(inteiros)

Gerando sequências

Gerar sequências no R é uma coisa muito fácil e divertida! Temos algumas formas para fazer isso:

#Gerando números de 1 a 10
1:10

#Gerando números de 10 a 1
10:1

#Gerando números de 100 a 120

seq(100, 120)

#Gerando 10 números a partir de 100

seq(100, length.out = 10)

#Gerando números de 10 a 20 de 2 em 2

seq.int(from = 10, to = 20, by = 2)

#Gerando 20 números

seq_len(20)

#Gerando um vetor do mesmo tamanho que o vetor passado

seq_along(c(70, 2))

#Repetindo o número 4 5 vezes

rep(4, times = 5)

NA, NaN, Inf, -Inf e NULL

Os tipos especiais são valores que possuem uma característica bem específica.

NA = Não disponível (Not Available) NaN = Não númerico (Not A Number) Inf = Infinito -Inf = -Infinito NULL = Vazio

Perceba que NA possui um tipo, mas NULL não, NULL representa o nada no caso do R e de diversas linguagens de programação.

Um detalhe é que não é possível colocar NULL em um vetor, ou seja, caso criemos um vetor com NULL, o R remove ele automáticamente

valor.na <- NA
valor.null <- NULL
valor.infinito <- Inf;
valor.menos.infinito <- -Inf
valor.nan <- NaN
vetor.com.null <- c(10,10,10,NULL)
vetor.com.null
[1] 10 10 10

Operações aritméticas

No R é possível fazer operações aritméticas entre os valores disponíveis, abaixo teremos exemplos para algumas operações aritméticas simples:


# Adição
adicao <- 5+5
adicao

# Subtração
subtracao <- 5-5
subtracao

# Multiplicação
multiplicao <- 5*5
multiplicao

# Divisão
divisao <- 5/5
divisao

#Raiz Quadrada

raiz <- sqrt(10)
raiz

#Numero imaginário
numero <- 1i
numero

Operações com vetores

As operações aritméticas se estendem a vetores também, veja abaixo um exemplo:

# Vetor de dez posições
vetor <- c(1:10)

vetor * 2

# Veja que obtemos o dobro de cada valor do vetor, isso se aplica para todas as operações.

Tipos avançados

Fatores

Através de fatores, é possível classificar dados para que as máquinas consigam processar com mais facilidade. Veja que no output, o R escreve “Levels: Feminino Masculino” para identificar as classes encontradas.

sexo <- c("Feminino", "Masculino","Feminino", "Masculino","Feminino", "Masculino","Feminino", "Masculino","Feminino", "Masculino")
fatorado <- as.factor(sexo);
fatorado
 [1] Feminino  Masculino Feminino  Masculino Feminino  Masculino Feminino  Masculino
 [9] Feminino  Masculino
Levels: Feminino Masculino

Listas

No R, temos o tipo de lista onde é possível armazenar vetores com tipos diferentes:


v1 <- c(1, 2, 3);
v2 <- c(T, F, T);
v3 <- c("a", "b", "c");
lista <- list(v1, v2, v3)

class(lista)

lista

Matrizes

Matrizes são um conjunto de valores distribuídos em linhas e colunas. A visualização abaixo deve esclarecer melhor:

matriz <- matrix(ncol = 5, nrow = 5, data = 1:5)

matriz

Você deve ter percebido que também é possível atribuir uma matriz para uma variável com esse exemplo.

Vamos a um exemplo de operação com matrizes

matrizA <- matrix(ncol = 5, nrow = 5, data = 1:5)
matrizB <- matrix(ncol = 5, nrow = 5, data = 1:5)
# Esta operação abaixo não é uma multiplicação de matrizes, é apenas uma multiplicação de valores.
matriz <- matrizA * matrizB
matriz
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    1    1    1    1
[2,]    4    4    4    4    4
[3,]    9    9    9    9    9
[4,]   16   16   16   16   16
[5,]   25   25   25   25   25

Para fazermos uma multiplicaçáo de matrizes, precisamos seguir uma regra: a quantidade de colunas da matriz A deve ser equivalente a quantidade de linhas da matriz B.

Abaixo um exemplo de multiplicação de matrizes:

linhas <- 5
colunas <- 10
matrizA <- matrix(ncol = linhas, nrow = colunas, data = 1:2)
matrizB <- matrix(ncol = colunas, nrow = linhas, data = 1:2)
matrizA %*% matrizB
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
 [1,]    7    8    7    8    7    8    7    8    7     8
 [2,]   14   16   14   16   14   16   14   16   14    16
 [3,]    7    8    7    8    7    8    7    8    7     8
 [4,]   14   16   14   16   14   16   14   16   14    16
 [5,]    7    8    7    8    7    8    7    8    7     8
 [6,]   14   16   14   16   14   16   14   16   14    16
 [7,]    7    8    7    8    7    8    7    8    7     8
 [8,]   14   16   14   16   14   16   14   16   14    16
 [9,]    7    8    7    8    7    8    7    8    7     8
[10,]   14   16   14   16   14   16   14   16   14    16

Funções úteis para matrizes

matrizA <- matrix(ncol = 2, nrow = 2, data = 1:4)
print("Dimensões da matriz - Linhas x Colunas")
[1] "Dimensões da matriz - Linhas x Colunas"
dim(matrizA)  #inversa, esta deve ser quadrada
[1] 2 2
print("Transposta")
[1] "Transposta"
t(matrizA) #transposta
     [,1] [,2]
[1,]    1    2
[2,]    3    4
print("Identidade")
[1] "Identidade"
diag(matrizA) #identidade
[1] 1 4
print("Inversa")
[1] "Inversa"
solve(matrizA)  #inversa, esta deve ser quadrada
     [,1] [,2]
[1,]   -2  1.5
[2,]    1 -0.5
matrizA <- cbind(matrizA, c(5,2)) #Adiciona colunas no fim da matriz
#Colunas adicionadas
print("Colunas adicionadas")
[1] "Colunas adicionadas"
matrizA
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    2
print("Linhas adicionadas")
[1] "Linhas adicionadas"
matrizA <- rbind(matrizA, c(5,2, 3))
matrizA
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    2
[3,]    5    2    3

Data Frame

Criar um dataframe é bem simples, veja:

vetorA <- c(1,5,4,7)
vetorB <- c("Olá mundo")
dataframe <- data.frame(vetorA, vetorB)
# Colocando nomes nas colunas
colnames(dataframe) <- c("Numérico", "Texto")
dataframe

O mais legal do dataframe, é que conseguimos colocar dados heterogêneos, ao contrário dos vetores e matrizes.

Também é possível criar um dataframe a partir de uma lista:

lista <- list(c(1,2), c(T,F), c("teste", "teste2"))
dataframe <- data.frame(lista)
dataframe

Datas

Geralmente o trabalho com datas é uma das coisas mais complexas em programação. Vamos ver aqui algumas funções que o R disponibiliza para nós:

data.texto = "13/11/2018 T 19:10:00"
data.date = as.Date(data.texto,format="%d/%m/%Y T %H:%M:%S",tz="America/Sao_Paulo")
data.time1 = as.POSIXct(data.texto,format="%d/%m/%Y T %H:%M:%S",tz="America/Sao_Paulo")
data.time2 = as.POSIXlt(data.texto,format="%d/%m/%Y T %H:%M:%S",tz="America/Sao_Paulo")
data.time1
[1] "2018-11-13 19:10:00 -02"
data.time2
[1] "2018-11-13 19:10:00 -02"
data.date 
[1] "2018-11-13"

Através do método unclass, podemos ver o conteúdo real de uma variável, suas propriedades e etc. Quando passamos data.date para a função unclass, obtemos a quantidade de dias desde 01/01/1970 até a data da variável.

unclass(data.date)
[1] 17848

No caso de time1 e time2 veja que não temos diferenças no texto, entretanto veja quando fazemos o unclass.

print("Time1")
[1] "Time1"
unclass(data.time1)
[1] 1542143400
attr(,"tzone")
[1] "America/Sao_Paulo"
print("Time2")
[1] "Time2"
unclass(data.time2)
$`sec`
[1] 0

$min
[1] 10

$hour
[1] 19

$mday
[1] 13

$mon
[1] 10

$year
[1] 118

$wday
[1] 2

$yday
[1] 316

$isdst
[1] 1

$zone
[1] "-02"

$gmtoff
[1] NA

attr(,"tzone")
[1] "America/Sao_Paulo"

O unclass no time1 retorna a contagem em segundos desde 01/01/1970 até a data da variável!!

Para obter a data atual

Sys.Date()
[1] "2018-12-01"

Lubridate

Lubridate é um pacote disponibilizado para manipular datas no R. Para instalar e carregar:

install.packages("lubridate")
Installing package into <U+393C><U+3E31>C:/Users/sergio.prates/Documents/R/win-library/3.5<U+393C><U+3E32>
(as <U+393C><U+3E31>lib<U+393C><U+3E32> is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.5/lubridate_1.7.4.zip'
Content type 'application/zip' length 1568280 bytes (1.5 MB)
downloaded 1.5 MB
package ‘lubridate’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\sergio.prates\AppData\Local\Temp\RtmpgpS10z\downloaded_packages
library(lubridate)

Attaching package: <U+393C><U+3E31>lubridate<U+393C><U+3E32>

The following object is masked from <U+393C><U+3E31>package:base<U+393C><U+3E32>:

    date

O lubridate fornece funções que retornarão a data no formato solicitado e além disso ele trabalha com o conceito de duração.

segundos  = dseconds(260)
minutos  = dminutes(260)
anos  = dyears(260)
duration(10, units = "seconds")
[1] "10s"
segundos
[1] "260s (~4.33 minutes)"
minutos
[1] "15600s (~4.33 hours)"
anos
[1] "8199360000s (~259.82 years)"
#abaixo as funções de data
#Ano mes dia
data <- ymd("20190101")
# Dia mes ano hora
dmy_h("1110201810")
[1] "2018-10-11 10:00:00 UTC"
# Retorna o dia da semana
wday(data, label = T)
[1] Tue
Levels: Sun < Mon < Tue < Wed < Thu < Fri < Sat

Estruturas de controle

Para tomar algumas decisões durante a execução de código, o R fornece algumas estruturas de controle.

souBonito <- TRUE
if (souBonito) {
  print("Eu Sei")
} else {
  print("Vish")
}
[1] "Eu Sei"
souBonito <- F
ifelse(souBonito, "verdade", "falso")
[1] "falso"

Estruturas de controle são muito úteis quando você precisa testar algum tipo de condição, se alguma compra foi realizada por exemplo, ou se algo ocorreu.

Estruturas de repetição = loops

Loops são utilizados quando precisamos por exemplo repetir um conjunto de instruções para determinados itens.

itens <- c(10,20,30)
for (variable in itens) {
  print(variable)
}
[1] 10
[1] 20
[1] 30

Veja que escrevemos todos os itens do vetor na tela, podemos utilizar para consolidar informações e enfim, para qualquer conjunto de instruções que precise se repetir.

Vamos montar um dataframe com um loop

vetor <- 1:10
acumulado <- 0
tabela <- data.frame();
for (variable in vetor) {
  acumulado <- variable + acumulado
   tabela <- rbind(tabela, c(variable, acumulado))
}
colnames(tabela) <- c("Valor1", "Acumulado")
tabela

Funções

Funções são utilizadas quando queremos reaproveitar algum trecho de código específico. por exemplo, digamos que precisamos calcular o enesimo termo de uma Progressão Aritmética

primeiro.termo <- 1
razao<- 2
obter.termo.pa <- function(primeiro.termo, numero.termo, razao) {
  return(primeiro.termo + (numero.termo - 1) * razao)
}
obter.termo.pa(primeiro.termo, 50, razao)
[1] 99

Em funções, podemos receber reticências como parametro, que significa que podemos receber N parametros na função. Um exemplo de função assim é a função paste.

concatena <- function(...) {
  c <- paste(...)
  c
}
concatena("Sergio", "Prates")
[1] "Sergio Prates"

Amostras

No R possuimos a função sample para randomizar a ocorrência de determinados valores

# Letras de a até g
amostra1 <- letters[1:7]
# Letras de A até D
amostra2 <- LETTERS[1:4]
# Pode repetir as ocorrências
sample(x = amostra1, size = 20, replace = T)
 [1] "a" "d" "f" "a" "e" "a" "g" "d" "d" "e" "e" "b" "d" "g" "a" "a" "d" "e" "c" "c"
# Não pode repetir as ocorrências
sample(x = amostra2, size = 3,  replace = F)
[1] "C" "D" "A"

Para garantir que sempre o mesmo resultado aconteça, podemos utilizar a função set.seed com um valor fixo

set.seed(1)
sample(x = amostra1, size = 20, replace = T)
 [1] "b" "c" "e" "g" "b" "g" "g" "e" "e" "a" "b" "b" "e" "c" "f" "d" "f" "g" "c" "f"

Simulações

O R nos fornecea alguns comandos para gerar dados aleatórios, sendo eles da família normal, binomial e uniforme.

Os comandos da familia normal possuem norm no final, os binomiais possuem binom e assim por diante… Veja abaixo exemplos:

set.seed(18) #garantindo que sempre sairá o mesmo resultado
# sd representa o desvio padrão dos dados
print("rnorm")
[1] "rnorm"
rnorm(n=10, mean=0, sd=1)
 [1]  0.92645924  1.82282117 -1.61056690 -0.28510975 -0.34207303  0.36617615
 [7] -1.32704085  2.41259221  0.06381535  1.54551478
print("dnorm")
[1] "dnorm"
dnorm(x = 1:10, mean = 0, sd = 1)
 [1] 2.419707e-01 5.399097e-02 4.431848e-03 1.338302e-04 1.486720e-06 6.075883e-09
 [7] 9.134720e-12 5.052271e-15 1.027977e-18 7.694599e-23
print("pnorm")
[1] "pnorm"
pnorm( q = 1:10, mean = 0, sd = 1)
 [1] 0.8413447 0.9772499 0.9986501 0.9999683 0.9999997 1.0000000 1.0000000 1.0000000
 [9] 1.0000000 1.0000000
print("rbinom")
[1] "rbinom"
rbinom(size = 1:10, prob = c(0.1,0.1,0.1,0.1,0.1,0.1,1,1,1,1), n = 10)
 [1]  0  0  1  1  0  1  7  8  9 10
print("dbinom")
[1] "dbinom"
dbinom(size = 1:10, prob = c(0.1,0.1,0.1,0.1,0.1,0.1,1,1,1,1), x = 1:10)
 [1] 1e-01 1e-02 1e-03 1e-04 1e-05 1e-06 1e+00 1e+00 1e+00 1e+00
print("pbinom")
[1] "pbinom"
pbinom(q = 1:10, size = 1:10, prob = c(0.1,0.1,0.1,0.1,0.1,0.1,1,1,1,1))
 [1] 1 1 1 1 1 1 1 1 1 1
print("Distribuição de poison")
[1] "Distribuição de poison"
rpois(100, 5)
  [1]  5  5  3  4  8  5  3  3  3  6  8  5  6  5  2  2  7  1  3  5  3  3  6  6  1  4  3
 [28]  7  5  5  4  2  1  3  3  6  5 12  6  7  8  4  2 10  7  4  6  5  2  3  6  5  7  5
 [55]  6  6 11  5  6  7  7  4  5  3  6  6  7  4  2  6  4  6  4  6  3  4  3  7  6 13  4
 [82]  3  5  3  1  4  3  5  8  8  5  6  6  6  3  6  5  3  2  1

Plots básico

Para fazer plots, ou gráficos em R podemos utilizar a função plot()

plot(x = cars$speed, y = cars$dist, type = "p", xlab = "Velocidade", ylab = "Distância", main = "Distância x Velocidade")

plot(x = cars$speed, y = cars$dist, type = "l", xlab = "Velocidade", ylab = "Distância", main = "Distância x Velocidade")

plot(x = cars$speed, y = cars$dist, type = "h", xlab = "Velocidade", ylab = "Distância", main = "Distância x Velocidade")

Usando outra biblioteca…

Podemos utilizar a equação abaixo para plotar um gráfico linear \(y = \beta_0 + \beta_1 + \epsilon\)

Onde

\(\beta_0 = 0,5\)

\(\beta_1 = 2,0\)

\(x\sim N(0;1²)\)

\(\epsilon\sim N(0;2²)\)

#install.packages('plotly')
library(plotly)
set.seed(5)
x = rnorm(n=350, mean=0, sd=1)
e = rnorm(n=350, mean=0, sd=2)
y=0.5 + 2*x + e
plot(x=x, y=y)

plot_ly(x=x, y=y, type="scatter", mode="markers")

Baixando dados externos

Com a função download file podemos baixar arquivos da web, neste caso ele sempre trata como texto os dados.


baixar <- function(url) {
  
  #Cria a pasta caso não exista
  
  if(!file.exists('data')){
    dir.create('data')
  }
  
  file.url = url
  file.local = file.path('./data', basename(file.url))
  download.file(url = file.url, destfile = file.local , mode='wb')
}

baixar('https://raw.githubusercontent.com/elthonf/fiap-mba-r/master/data/Copas.csv')
baixar('https://raw.githubusercontent.com/elthonf/fiap-mba-r/master/data/Copas-Partidas.csv')
baixar('https://raw.githubusercontent.com/elthonf/fiap-mba-r/master/data/Copas-Jogadores.csv')
baixar('https://github.com/elthonf/fiap-mba-r/raw/master/data/cameras.baltimore.xlsx')

Lendo dados de csv’s

Para ler dados de csvs podemos utilizar a função read.csv

copas <- read.csv('./data/Copas.csv', header = T)
copas

Para ler dados do excel, podemos utilizar o pacote

install.packages('readxl')
Installing package into <U+393C><U+3E31>C:/Users/sergio.prates/Documents/R/win-library/3.5<U+393C><U+3E32>
(as <U+393C><U+3E31>lib<U+393C><U+3E32> is unspecified)
also installing the dependencies <U+393C><U+3E31>rematch<U+393C><U+3E32>, <U+393C><U+3E31>cellranger<U+393C><U+3E32>

trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.5/rematch_1.0.1.zip'
Content type 'application/zip' length 15994 bytes (15 KB)
downloaded 15 KB

trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.5/cellranger_1.1.0.zip'
Content type 'application/zip' length 103141 bytes (100 KB)
downloaded 100 KB

trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.5/readxl_1.1.0.zip'
Content type 'application/zip' length 1499856 bytes (1.4 MB)
downloaded 1.4 MB
package ‘rematch’ successfully unpacked and MD5 sums checked
package ‘cellranger’ successfully unpacked and MD5 sums checked
package ‘readxl’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\sergio.prates\AppData\Local\Temp\RtmpOqvMmO\downloaded_packages
library(readxl)

Manipulando estruturas de tabelas com dplyr

O pacote dplyr nos ajuda a manipular estruturas de tabelas de maneira bastante eficiente.

Abaixo utilizamos o pipe para passar o conteúdo

install.packages('dplyr')
Error in install.packages : Updating loaded packages
library(dplyr)

Attaching package: <U+393C><U+3E31>dplyr<U+393C><U+3E32>

The following objects are masked from <U+393C><U+3E31>package:stats<U+393C><U+3E32>:

    filter, lag

The following objects are masked from <U+393C><U+3E31>package:base<U+393C><U+3E32>:

    intersect, setdiff, setequal, union
LS0tDQp0aXRsZTogIlByb2dyYW1hbmRvIElBIGNvbSBSIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KDQojIyMjIFBvcnRm82xpbw0KDQojIyMgQ29uY2VpdG9zIGRlIHZhcmnhdmVpcw0KDQoNCioqVmV0b3IqKg0KDQpUb2RhIHZhcmnhdmVsIG5vIFIg6SB1bSB2ZXRvciwgdW0gdmV0b3IgcG9kZSB2aXN0byBjb21vIHVtIGNvbmp1bnRvIGRlIHZhbG9yZXMgbGluZWFyIGUgaG9tb2fqbmVvLg0KDQpQYXJhIGF0cmlidWlyIHVtIHZhbG9yIOAgdW1hIHZhcmnhdmVsLCB1dGlsaXphbW9zIGEgc2V0YSA8LSBpbmRpY2FuZG8gcGFyYSBvbmRlIGVzdGFtb3MgZGlyZWNpb25hbmRvIG8gdmFsb3IuDQoNCskgaW1wb3J0YW50ZSBzYWJlciB0YW1i6W0sIHF1ZSBwYXJhIGNyaWFyIHVtIHZldG9yIGNvbSB2YWxvcmVzLCBwb2RlbW9zIHV0aWxpemFyIGEgZnVu5+NvIGMoKSBxdWUgY29tYmluYSBvcyB2YWxvcmVzIGVtIHVtIHZldG9yDQoNClNlbmRvIGFzc2ltLCBhYmFpeG8gZXN0YW1vcyBjcmlhbmRvIGEgdmFyaeF2ZWwgdmV0b3IgZSBhdHJpYnVpbmRvIG8gdmFsb3IgMSA1IDQNCg0KYGBge3J9DQp2ZXRvciA8LSBjKDEsIDUsIDQpDQoNCnZldG9yDQpgYGANCg0KDQojIyMgVGlwb3MgZGUgdmFsb3Jlcw0KDQoqKk51belyaWNvcyBlIENhcmFjdGVyZXMqKg0KDQoNCk5vIFIgdGVtcG9zIG8gY29uY2VpdG8gZGUgdGlwb3MsIG9uZGUgY2FkYSB2YWxvciB0ZW0gdW0gdGlwbyBlc3BlY+1maWNvLCBsZW1icmEgZGFzIGF1bGFzIGRlIG1hdGVt4XRpY2Egc29icmUgaW50ZWlyb3MsIGRlY2ltYWlzLCBldGM/DQoNClBhcmEgdmVyaWZpY2FyIG8gdGlwbyBpbnRlcnByZXRhZG8gcGVsbyBSIGRlIHVtIHZhbG9yLCBwb2RlbW9zIHV0aWxpemFyIGEgZnVu5+NvIGNsYXNzKHZhbG9yKSwgb25kZSB2YWxvciDpIGlndWFsIGFvIHZhbG9yIHF1ZSB2b2PqIHF1ZXIgdmVyaWZpY2FyLg0KDQpgYGB7cn0NCmNsYXNzKDUpDQpjbGFzcygiT2zhIG11bmRvIikNCmBgYA0KDQoNCioqUmVjb25oZWNlbmRvIHRpcG9zIGRlIHZhcmnhdmVpcyoqDQoNClZlamEgcXVlIG8gUiByZWNvbmhlY2V1IG8gdmFsb3IgNSBjb21vIG76bWVyaWNvIGUgbyB0ZXh0byAiT2zhIG11bmRvIiBjb21vIHVtIGNvbmp1bnRvIGRlIGNhcmFjdGVyZXMuDQoNCklzdG8gdGFtYultIHNlIGFwbGljYSBhIHZhcmnhdmVpcywgdmVqYSBz8zoNCg0KYGBge3J9DQp2YXJpYXZlbF9udW1lcmljYSA8LSBjKDEsNSw0LDcpDQp2YXJpYXZlbF9jYXJhY3RlcmVzIDwtIGMoIk9s4SBtdW5kbyIpDQoNCmNsYXNzKHZhcmlhdmVsX251bWVyaWNhKQ0KY2xhc3ModmFyaWF2ZWxfY2FyYWN0ZXJlcykNCmBgYA0KDQoNClRhbWLpbSBwb2RlbW9zIHVzYXIgYXMgZnVu5/VlcyBkaXNwb27tdmVpcyBlbSAiaXMiIHBhcmEgdmVyaWZpY2FyIG9zIHRpcG9zLCBlc3NhIHZlcmlmaWNh5+NvIHJldG9ybmEgdW0gdGlwbyBs82dpY28gcGFyYSBu83MNCmBgYHtyfQ0KdmFyaWF2ZWwgPC0gIjUiDQppcy5udW1lcmljKHZhcmlhdmVsKQ0KaXMuY2hhcmFjdGVyKHZhcmlhdmVsKQ0KYGBgDQoNCg0KDQoqKkzzZ2ljb3MqKg0KDQpObyBSLCB0YW1i6W0g6SBwb3Nz7XZlbCBjcmlhciB0aXBvcyBs82dpY29zICh2ZXJkYWRlaXJvIG91IGZhbHNvKQ0KDQpgYGB7cn0NCmxvZ2ljb3MgPC0gYyhUUlVFLCBGQUxTRSwgVFJVRSkNCmxvZ2ljb3MyIDwtIGMoVCwgRiwgVCkNCg0KbG9naWNvcw0KbG9naWNvczINCg0KY2xhc3MobG9naWNvcykNCmBgYA0KDQoNClZlamEgcXVlIOkgcG9zc+12ZWwgYWJyZXZpYXIgYXMgZGVjbGFyYef1ZXMuIA0KDQoqKkludGVpcm9zIEV4cGxpY2l0b3MqKg0KDQpWb2PqIGRldmUgdGVyIHBlcmNlYmlkbyBxdWUgbm8gY2FzbyBkbyB0aXBvIG51belyaWNvLCBvIHRpcG8gbuNvIGZvaSBkZWNsYXJhZG8gZXhwbGljaXRhbWVudGUgY29tbyBpbnRlaXJvLCBwYXJhIGZhemVyIGlzc28gdmVqYSBvIHBy83hpbW8gdHJlY2hvOg0KDQpgYGB7cn0NCmludGVpcm9zIDwtIGMoMUwsIDJMLCAzTCkNCg0KaW50ZWlyb3MNCmNsYXNzKGludGVpcm9zKQ0KYGBgDQoNCg0KIyMjIEdlcmFuZG8gc2VxdepuY2lhcw0KDQpHZXJhciBzZXF16m5jaWFzIG5vIFIg6SB1bWEgY29pc2EgbXVpdG8gZuFjaWwgZSBkaXZlcnRpZGEhIFRlbW9zIGFsZ3VtYXMgZm9ybWFzIHBhcmEgIGZhemVyIGlzc286DQoNCmBgYHtyfQ0KI0dlcmFuZG8gbvptZXJvcyBkZSAxIGEgMTANCjE6MTANCg0KI0dlcmFuZG8gbvptZXJvcyBkZSAxMCBhIDENCjEwOjENCg0KI0dlcmFuZG8gbvptZXJvcyBkZSAxMDAgYSAxMjANCg0Kc2VxKDEwMCwgMTIwKQ0KDQojR2VyYW5kbyAxMCBu+m1lcm9zIGEgcGFydGlyIGRlIDEwMA0KDQpzZXEoMTAwLCBsZW5ndGgub3V0ID0gMTApDQoNCiNHZXJhbmRvIG76bWVyb3MgZGUgMTAgYSAyMCBkZSAyIGVtIDINCg0Kc2VxLmludChmcm9tID0gMTAsIHRvID0gMjAsIGJ5ID0gMikNCg0KI0dlcmFuZG8gMjAgbvptZXJvcw0KDQpzZXFfbGVuKDIwKQ0KDQojR2VyYW5kbyB1bSB2ZXRvciBkbyBtZXNtbyB0YW1hbmhvIHF1ZSBvIHZldG9yIHBhc3NhZG8NCg0Kc2VxX2Fsb25nKGMoNzAsIDIpKQ0KDQojUmVwZXRpbmRvIG8gbvptZXJvIDQgNSB2ZXplcw0KDQpyZXAoNCwgdGltZXMgPSA1KQ0KDQpgYGANCg0KKipOQSwgTmFOLCBJbmYsIC1JbmYgZSBOVUxMKioNCg0KT3MgdGlwb3MgZXNwZWNpYWlzIHPjbyB2YWxvcmVzIHF1ZSBwb3NzdWVtIHVtYSBjYXJhY3Rlcu1zdGljYSBiZW0gZXNwZWPtZmljYS4NCg0KTkEgPSBO428gZGlzcG9u7XZlbCAoTm90IEF2YWlsYWJsZSkNCk5hTiA9IE7jbyBu+m1lcmljbyAoTm90IEEgTnVtYmVyKQ0KSW5mID0gSW5maW5pdG8NCi1JbmYgPSAtSW5maW5pdG8NCk5VTEwgPSBWYXppbw0KDQpQZXJjZWJhIHF1ZSBOQSBwb3NzdWkgdW0gdGlwbywgbWFzIE5VTEwgbuNvLCBOVUxMIHJlcHJlc2VudGEgbyBuYWRhIG5vIGNhc28gZG8gUiBlIGRlIGRpdmVyc2FzIGxpbmd1YWdlbnMgZGUgcHJvZ3JhbWHn428uDQoNClVtIGRldGFsaGUg6SBxdWUgbuNvIOkgcG9zc+12ZWwgY29sb2NhciBOVUxMIGVtIHVtIHZldG9yLCBvdSBzZWphLCBjYXNvIGNyaWVtb3MgdW0gdmV0b3IgY29tIE5VTEwsIG8gUiByZW1vdmUgZWxlIGF1dG9t4XRpY2FtZW50ZQ0KDQpgYGB7cn0NCnZhbG9yLm5hIDwtIE5BDQp2YWxvci5udWxsIDwtIE5VTEwNCnZhbG9yLmluZmluaXRvIDwtIEluZjsNCnZhbG9yLm1lbm9zLmluZmluaXRvIDwtIC1JbmYNCnZhbG9yLm5hbiA8LSBOYU4NCg0KdmV0b3IuY29tLm51bGwgPC0gYygxMCwxMCwxMCxOVUxMKQ0KDQp2ZXRvci5jb20ubnVsbA0KYGBgDQoNCg0KIyMjIE9wZXJh5/VlcyBhcml0bel0aWNhcw0KDQpObyBSIOkgcG9zc+12ZWwgZmF6ZXIgb3BlcmHn9WVzIGFyaXRt6XRpY2FzIGVudHJlIG9zIHZhbG9yZXMgZGlzcG9u7XZlaXMsIGFiYWl4byB0ZXJlbW9zIGV4ZW1wbG9zIHBhcmEgYWxndW1hcyBvcGVyYef1ZXMgYXJpdG3pdGljYXMgc2ltcGxlczoNCmBgYHtyfQ0KDQojIEFkaefjbw0KYWRpY2FvIDwtIDUrNQ0KYWRpY2FvDQoNCiMgU3VidHJh5+NvDQpzdWJ0cmFjYW8gPC0gNS01DQpzdWJ0cmFjYW8NCg0KIyBNdWx0aXBsaWNh5+NvDQptdWx0aXBsaWNhbyA8LSA1KjUNCm11bHRpcGxpY2FvDQoNCiMgRGl2aXPjbw0KZGl2aXNhbyA8LSA1LzUNCmRpdmlzYW8NCg0KI1JhaXogUXVhZHJhZGENCg0KcmFpeiA8LSBzcXJ0KDEwKQ0KcmFpeg0KDQojTnVtZXJvIGltYWdpbuFyaW8NCm51bWVybyA8LSAxaQ0KbnVtZXJvDQpgYGANCg0KKipPcGVyYef1ZXMgY29tIHZldG9yZXMqKg0KDQpBcyBvcGVyYef1ZXMgYXJpdG3pdGljYXMgc2UgZXN0ZW5kZW0gYSB2ZXRvcmVzIHRhbWLpbSwgdmVqYSBhYmFpeG8gdW0gZXhlbXBsbzoNCg0KYGBge3J9DQojIFZldG9yIGRlIGRleiBwb3Np5/Vlcw0KdmV0b3IgPC0gYygxOjEwKQ0KDQp2ZXRvciAqIDINCg0KIyBWZWphIHF1ZSBvYnRlbW9zIG8gZG9icm8gZGUgY2FkYSB2YWxvciBkbyB2ZXRvciwgaXNzbyBzZSBhcGxpY2EgcGFyYSB0b2RhcyBhcyBvcGVyYef1ZXMuDQoNCmBgYA0KDQoNCg0KIyMjIFRpcG9zIGF2YW7nYWRvcw0KDQoqKkZhdG9yZXMqKg0KDQpBdHJhdulzIGRlIGZhdG9yZXMsIOkgcG9zc+12ZWwgY2xhc3NpZmljYXIgZGFkb3MgcGFyYSBxdWUgYXMgbeFxdWluYXMgY29uc2lnYW0gcHJvY2Vzc2FyIGNvbSBtYWlzIGZhY2lsaWRhZGUuIFZlamEgcXVlIG5vIG91dHB1dCwgbyBSIGVzY3JldmUgIkxldmVsczogRmVtaW5pbm8gTWFzY3VsaW5vIiBwYXJhIGlkZW50aWZpY2FyIGFzIGNsYXNzZXMgZW5jb250cmFkYXMuDQpgYGB7cn0NCnNleG8gPC0gYygiRmVtaW5pbm8iLCAiTWFzY3VsaW5vIiwiRmVtaW5pbm8iLCAiTWFzY3VsaW5vIiwiRmVtaW5pbm8iLCAiTWFzY3VsaW5vIiwiRmVtaW5pbm8iLCAiTWFzY3VsaW5vIiwiRmVtaW5pbm8iLCAiTWFzY3VsaW5vIikNCg0KZmF0b3JhZG8gPC0gYXMuZmFjdG9yKHNleG8pOw0KDQpmYXRvcmFkbw0KYGBgDQoNCg0KKipMaXN0YXMqKg0KDQpObyBSLCB0ZW1vcyBvIHRpcG8gZGUgbGlzdGEgb25kZSDpIHBvc3PtdmVsIGFybWF6ZW5hciB2ZXRvcmVzIGNvbSB0aXBvcyBkaWZlcmVudGVzOg0KYGBge3J9DQoNCnYxIDwtIGMoMSwgMiwgMyk7DQp2MiA8LSBjKFQsIEYsIFQpOw0KdjMgPC0gYygiYSIsICJiIiwgImMiKTsNCmxpc3RhIDwtIGxpc3QodjEsIHYyLCB2MykNCg0KY2xhc3MobGlzdGEpDQoNCmxpc3RhDQpgYGANCg0KDQoNCioqTWF0cml6ZXMqKg0KDQpNYXRyaXplcyBz428gdW0gY29uanVudG8gZGUgdmFsb3JlcyBkaXN0cmlide1kb3MgZW0gbGluaGFzIGUgY29sdW5hcy4gQSB2aXN1YWxpemHn428gYWJhaXhvIGRldmUgZXNjbGFyZWNlciBtZWxob3I6DQpgYGB7cn0NCm1hdHJpeiA8LSBtYXRyaXgobmNvbCA9IDUsIG5yb3cgPSA1LCBkYXRhID0gMTo1KQ0KDQptYXRyaXoNCmBgYA0KDQpWb2PqIGRldmUgdGVyIHBlcmNlYmlkbyBxdWUgdGFtYultIOkgcG9zc+12ZWwgYXRyaWJ1aXIgdW1hIG1hdHJpeiBwYXJhIHVtYSB2YXJp4XZlbCBjb20gZXNzZSBleGVtcGxvLg0KDQpWYW1vcyBhIHVtIGV4ZW1wbG8gZGUgb3BlcmHn428gY29tIG1hdHJpemVzDQpgYGB7cn0NCm1hdHJpekEgPC0gbWF0cml4KG5jb2wgPSA1LCBucm93ID0gNSwgZGF0YSA9IDE6NSkNCm1hdHJpekIgPC0gbWF0cml4KG5jb2wgPSA1LCBucm93ID0gNSwgZGF0YSA9IDE6NSkNCg0KIyBFc3RhIG9wZXJh5+NvIGFiYWl4byBu428g6SB1bWEgbXVsdGlwbGljYefjbyBkZSBtYXRyaXplcywg6SBhcGVuYXMgdW1hIG11bHRpcGxpY2Hn428gZGUgdmFsb3Jlcy4NCm1hdHJpeiA8LSBtYXRyaXpBICogbWF0cml6Qg0KDQptYXRyaXoNCmBgYA0KDQpQYXJhIGZhemVybW9zIHVtYSBtdWx0aXBsaWNh5+FvIGRlIG1hdHJpemVzLCBwcmVjaXNhbW9zIHNlZ3VpciB1bWEgcmVncmE6IGEgcXVhbnRpZGFkZSBkZSBjb2x1bmFzIGRhIG1hdHJpeiBBIGRldmUgc2VyIGVxdWl2YWxlbnRlIGEgcXVhbnRpZGFkZSBkZSBsaW5oYXMgZGEgbWF0cml6IEIuDQoNCkFiYWl4byB1bSBleGVtcGxvIGRlIG11bHRpcGxpY2Hn428gZGUgbWF0cml6ZXM6DQpgYGB7cn0NCmxpbmhhcyA8LSA1DQpjb2x1bmFzIDwtIDEwDQoNCm1hdHJpekEgPC0gbWF0cml4KG5jb2wgPSBsaW5oYXMsIG5yb3cgPSBjb2x1bmFzLCBkYXRhID0gMToyKQ0KbWF0cml6QiA8LSBtYXRyaXgobmNvbCA9IGNvbHVuYXMsIG5yb3cgPSBsaW5oYXMsIGRhdGEgPSAxOjIpDQoNCm1hdHJpekEgJSolIG1hdHJpekINCmBgYA0KDQoNCioqRnVu5/VlcyD6dGVpcyBwYXJhIG1hdHJpemVzKioNCg0KYGBge3J9DQptYXRyaXpBIDwtIG1hdHJpeChuY29sID0gMiwgbnJvdyA9IDIsIGRhdGEgPSAxOjQpDQoNCnByaW50KCJEaW1lbnP1ZXMgZGEgbWF0cml6IC0gTGluaGFzIHggQ29sdW5hcyIpDQpkaW0obWF0cml6QSkgICNpbnZlcnNhLCBlc3RhIGRldmUgc2VyIHF1YWRyYWRhDQoNCnByaW50KCJUcmFuc3Bvc3RhIikNCnQobWF0cml6QSkgI3RyYW5zcG9zdGENCg0KcHJpbnQoIklkZW50aWRhZGUiKQ0KZGlhZyhtYXRyaXpBKSAjaWRlbnRpZGFkZQ0KDQpwcmludCgiSW52ZXJzYSIpDQpzb2x2ZShtYXRyaXpBKSAgI2ludmVyc2EsIGVzdGEgZGV2ZSBzZXIgcXVhZHJhZGENCg0KbWF0cml6QSA8LSBjYmluZChtYXRyaXpBLCBjKDUsMikpICNBZGljaW9uYSBjb2x1bmFzIG5vIGZpbSBkYSBtYXRyaXoNCg0KI0NvbHVuYXMgYWRpY2lvbmFkYXMNCnByaW50KCJDb2x1bmFzIGFkaWNpb25hZGFzIikNCm1hdHJpekENCg0KcHJpbnQoIkxpbmhhcyBhZGljaW9uYWRhcyIpDQptYXRyaXpBIDwtIHJiaW5kKG1hdHJpekEsIGMoNSwyLCAzKSkNCm1hdHJpekENCmBgYA0KDQoNCioqRGF0YSBGcmFtZSoqDQoNCkNyaWFyIHVtIGRhdGFmcmFtZSDpIGJlbSBzaW1wbGVzLCB2ZWphOg0KYGBge3J9DQoNCnZldG9yQSA8LSBjKDEsNSw0LDcpDQp2ZXRvckIgPC0gYygiT2zhIG11bmRvIikNCg0KZGF0YWZyYW1lIDwtIGRhdGEuZnJhbWUodmV0b3JBLCB2ZXRvckIpDQoNCiMgQ29sb2NhbmRvIG5vbWVzIG5hcyBjb2x1bmFzDQoNCmNvbG5hbWVzKGRhdGFmcmFtZSkgPC0gYygiTnVt6XJpY28iLCAiVGV4dG8iKQ0KDQpkYXRhZnJhbWUNCmBgYA0KDQpPIG1haXMgbGVnYWwgZG8gZGF0YWZyYW1lLCDpIHF1ZSBjb25zZWd1aW1vcyBjb2xvY2FyIGRhZG9zIGhldGVyb2fqbmVvcywgYW8gY29udHLhcmlvIGRvcyB2ZXRvcmVzIGUgbWF0cml6ZXMuDQoNClRhbWLpbSDpIHBvc3PtdmVsIGNyaWFyIHVtIGRhdGFmcmFtZSBhIHBhcnRpciBkZSB1bWEgbGlzdGE6DQpgYGB7cn0NCmxpc3RhIDwtIGxpc3QoYygxLDIpLCBjKFQsRiksIGMoInRlc3RlIiwgInRlc3RlMiIpKQ0KDQpkYXRhZnJhbWUgPC0gZGF0YS5mcmFtZShsaXN0YSkNCg0KZGF0YWZyYW1lDQpgYGANCg0KDQoqKkRhdGFzKioNCg0KR2VyYWxtZW50ZSBvIHRyYWJhbGhvIGNvbSBkYXRhcyDpIHVtYSBkYXMgY29pc2FzIG1haXMgY29tcGxleGFzIGVtIHByb2dyYW1h5+NvLiBWYW1vcyB2ZXIgYXF1aSBhbGd1bWFzIGZ1buf1ZXMgcXVlIG8gUiBkaXNwb25pYmlsaXphIHBhcmEgbvNzOg0KYGBge3J9DQpkYXRhLnRleHRvID0gIjEzLzExLzIwMTggVCAxOToxMDowMCINCmRhdGEuZGF0ZSA9IGFzLkRhdGUoZGF0YS50ZXh0byxmb3JtYXQ9IiVkLyVtLyVZIFQgJUg6JU06JVMiLHR6PSJBbWVyaWNhL1Nhb19QYXVsbyIpDQpkYXRhLnRpbWUxID0gYXMuUE9TSVhjdChkYXRhLnRleHRvLGZvcm1hdD0iJWQvJW0vJVkgVCAlSDolTTolUyIsdHo9IkFtZXJpY2EvU2FvX1BhdWxvIikNCmRhdGEudGltZTIgPSBhcy5QT1NJWGx0KGRhdGEudGV4dG8sZm9ybWF0PSIlZC8lbS8lWSBUICVIOiVNOiVTIix0ej0iQW1lcmljYS9TYW9fUGF1bG8iKQ0KZGF0YS50aW1lMQ0KZGF0YS50aW1lMg0KZGF0YS5kYXRlIA0KYGBgDQoNCkF0cmF26XMgZG8gbel0b2RvIHVuY2xhc3MsIHBvZGVtb3MgdmVyIG8gY29udGX6ZG8gcmVhbCBkZSB1bWEgdmFyaeF2ZWwsIHN1YXMgcHJvcHJpZWRhZGVzIGUgZXRjLg0KUXVhbmRvIHBhc3NhbW9zIGRhdGEuZGF0ZSBwYXJhIGEgZnVu5+NvIHVuY2xhc3MsIG9idGVtb3MgYSBxdWFudGlkYWRlIGRlIGRpYXMgZGVzZGUgMDEvMDEvMTk3MCBhdOkgYSBkYXRhIGRhIHZhcmnhdmVsLg0KDQpgYGB7cn0NCnVuY2xhc3MoZGF0YS5kYXRlKQ0KYGBgDQoNCg0KTm8gY2FzbyBkZSB0aW1lMSBlIHRpbWUyIHZlamEgcXVlIG7jbyB0ZW1vcyBkaWZlcmVu52FzIG5vIHRleHRvLCBlbnRyZXRhbnRvIHZlamEgcXVhbmRvIGZhemVtb3MgbyB1bmNsYXNzLg0KYGBge3J9DQpwcmludCgiVGltZTEiKQ0KdW5jbGFzcyhkYXRhLnRpbWUxKQ0KDQpwcmludCgiVGltZTIiKQ0KdW5jbGFzcyhkYXRhLnRpbWUyKQ0KYGBgDQoNCk8gdW5jbGFzcyBubyB0aW1lMSByZXRvcm5hIGEgY29udGFnZW0gZW0gc2VndW5kb3MgZGVzZGUgMDEvMDEvMTk3MCBhdOkgYSBkYXRhIGRhIHZhcmnhdmVsISENCg0KDQpQYXJhIG9idGVyIGEgZGF0YSBhdHVhbA0KYGBge3J9DQpTeXMuRGF0ZSgpDQpgYGANCg0KDQoNCioqTHVicmlkYXRlKioNCg0KTHVicmlkYXRlIOkgdW0gcGFjb3RlIGRpc3BvbmliaWxpemFkbyBwYXJhIG1hbmlwdWxhciBkYXRhcyBubyBSLg0KUGFyYSBpbnN0YWxhciBlIGNhcnJlZ2FyOg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJsdWJyaWRhdGUiKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpgYGANCg0KDQpPIGx1YnJpZGF0ZSBmb3JuZWNlIGZ1buf1ZXMgcXVlIHJldG9ybmFy428gYSBkYXRhIG5vIGZvcm1hdG8gc29saWNpdGFkbyBlIGFs6W0gZGlzc28gZWxlIHRyYWJhbGhhIGNvbSBvIGNvbmNlaXRvIGRlIGR1cmHn428uDQpgYGB7cn0NCnNlZ3VuZG9zICA9IGRzZWNvbmRzKDI2MCkNCm1pbnV0b3MgID0gZG1pbnV0ZXMoMjYwKQ0KYW5vcyAgPSBkeWVhcnMoMjYwKQ0KDQpkdXJhdGlvbigxMCwgdW5pdHMgPSAic2Vjb25kcyIpDQoNCnNlZ3VuZG9zDQptaW51dG9zDQphbm9zDQoNCiNhYmFpeG8gYXMgZnVu5/VlcyBkZSBkYXRhDQoNCiNBbm8gbWVzIGRpYQ0KZGF0YSA8LSB5bWQoIjIwMTkwMTAxIikNCg0KIyBEaWEgbWVzIGFubyBob3JhDQpkbXlfaCgiMTExMDIwMTgxMCIpDQoNCiMgUmV0b3JuYSBvIGRpYSBkYSBzZW1hbmENCndkYXkoZGF0YSwgbGFiZWwgPSBUKQ0KDQpgYGANCg0KDQoNCiMjIyBFc3RydXR1cmFzIGRlIGNvbnRyb2xlDQoNClBhcmEgdG9tYXIgYWxndW1hcyBkZWNpc/VlcyBkdXJhbnRlIGEgZXhlY3Xn428gZGUgY/NkaWdvLCBvIFIgZm9ybmVjZSBhbGd1bWFzIGVzdHJ1dHVyYXMgZGUgY29udHJvbGUuDQoNCmBgYHtyfQ0KDQpzb3VCb25pdG8gPC0gVFJVRQ0KDQppZiAoc291Qm9uaXRvKSB7DQogIHByaW50KCJFdSBTZWkiKQ0KfSBlbHNlIHsNCiAgcHJpbnQoIlZpc2giKQ0KfQ0KDQpzb3VCb25pdG8gPC0gRg0KaWZlbHNlKHNvdUJvbml0bywgInZlcmRhZGUiLCAiZmFsc28iKQ0KDQpgYGANCg0KRXN0cnV0dXJhcyBkZSBjb250cm9sZSBz428gbXVpdG8g+nRlaXMgcXVhbmRvIHZvY+ogcHJlY2lzYSB0ZXN0YXIgYWxndW0gdGlwbyBkZSBjb25kaefjbywgc2UgYWxndW1hIGNvbXByYSBmb2kgcmVhbGl6YWRhIHBvciBleGVtcGxvLCBvdSBzZSBhbGdvIG9jb3JyZXUuDQoNCiMjIyBFc3RydXR1cmFzIGRlIHJlcGV0aefjbyA9IGxvb3BzDQoNCg0KTG9vcHMgc+NvIHV0aWxpemFkb3MgcXVhbmRvIHByZWNpc2Ftb3MgcG9yIGV4ZW1wbG8gcmVwZXRpciB1bSBjb25qdW50byBkZSBpbnN0cnXn9WVzIHBhcmEgZGV0ZXJtaW5hZG9zIGl0ZW5zLg0KYGBge3J9DQppdGVucyA8LSBjKDEwLDIwLDMwKQ0KDQpmb3IgKHZhcmlhYmxlIGluIGl0ZW5zKSB7DQogIHByaW50KHZhcmlhYmxlKQ0KfQ0KYGBgDQoNClZlamEgcXVlIGVzY3JldmVtb3MgdG9kb3Mgb3MgaXRlbnMgZG8gdmV0b3IgbmEgdGVsYSwgcG9kZW1vcyB1dGlsaXphciBwYXJhIGNvbnNvbGlkYXIgaW5mb3JtYef1ZXMgZSBlbmZpbSwgcGFyYSBxdWFscXVlciBjb25qdW50byBkZSBpbnN0cnXn9WVzIHF1ZSBwcmVjaXNlIHNlIHJlcGV0aXIuDQoNClZhbW9zIG1vbnRhciB1bSBkYXRhZnJhbWUgY29tIHVtIGxvb3ANCg0KYGBge3J9DQp2ZXRvciA8LSAxOjEwDQphY3VtdWxhZG8gPC0gMA0KdGFiZWxhIDwtIGRhdGEuZnJhbWUoKTsNCmZvciAodmFyaWFibGUgaW4gdmV0b3IpIHsNCiAgYWN1bXVsYWRvIDwtIHZhcmlhYmxlICsgYWN1bXVsYWRvDQogICB0YWJlbGEgPC0gcmJpbmQodGFiZWxhLCBjKHZhcmlhYmxlLCBhY3VtdWxhZG8pKQ0KfQ0KDQpjb2xuYW1lcyh0YWJlbGEpIDwtIGMoIlZhbG9yMSIsICJBY3VtdWxhZG8iKQ0KdGFiZWxhDQoNCmBgYA0KDQoNCg0KDQojIyMgRnVu5/Vlcw0KDQpGdW7n9WVzIHPjbyB1dGlsaXphZGFzIHF1YW5kbyBxdWVyZW1vcyByZWFwcm92ZWl0YXIgYWxndW0gdHJlY2hvIGRlIGPzZGlnbyBlc3BlY+1maWNvLiBwb3IgZXhlbXBsbywgZGlnYW1vcyBxdWUgcHJlY2lzYW1vcyBjYWxjdWxhciBvIGVuZXNpbW8gdGVybW8gZGUgdW1hIFByb2dyZXNz428gQXJpdG3pdGljYQ0KDQpgYGB7cn0NCg0KcHJpbWVpcm8udGVybW8gPC0gMQ0KcmF6YW8gPC0gMg0KDQpvYnRlci50ZXJtby5wYSA8LSBmdW5jdGlvbihwcmltZWlyby50ZXJtbywgbnVtZXJvLnRlcm1vLCByYXphbykgew0KICByZXR1cm4ocHJpbWVpcm8udGVybW8gKyAobnVtZXJvLnRlcm1vIC0gMSkgKiByYXphbykNCn0NCg0Kb2J0ZXIudGVybW8ucGEocHJpbWVpcm8udGVybW8sIDUwLCByYXphbykNCmBgYA0KDQpFbSBmdW7n9WVzLCBwb2RlbW9zIHJlY2ViZXIgcmV0aWPqbmNpYXMgY29tbyBwYXJhbWV0cm8sIHF1ZSBzaWduaWZpY2EgcXVlIHBvZGVtb3MgcmVjZWJlciBOIHBhcmFtZXRyb3MgbmEgZnVu5+NvLiBVbSBleGVtcGxvIGRlIGZ1bufjbyBhc3NpbSDpIGEgZnVu5+NvIHBhc3RlLg0KYGBge3J9DQoNCmNvbmNhdGVuYSA8LSBmdW5jdGlvbiguLi4pIHsNCiAgYyA8LSBwYXN0ZSguLi4pDQogIGMNCn0NCg0KY29uY2F0ZW5hKCJTZXJnaW8iLCAiUHJhdGVzIikNCmBgYA0KDQoNCg0KIyMjIEFtb3N0cmFzDQoNCk5vIFIgcG9zc3VpbW9zIGEgZnVu5+NvIHNhbXBsZSBwYXJhIHJhbmRvbWl6YXIgYSBvY29ycupuY2lhIGRlIGRldGVybWluYWRvcyB2YWxvcmVzDQpgYGB7cn0NCg0KIyBMZXRyYXMgZGUgYSBhdOkgZw0KYW1vc3RyYTEgPC0gbGV0dGVyc1sxOjddDQoNCiMgTGV0cmFzIGRlIEEgYXTpIEQNCmFtb3N0cmEyIDwtIExFVFRFUlNbMTo0XQ0KDQojIFBvZGUgcmVwZXRpciBhcyBvY29ycupuY2lhcw0Kc2FtcGxlKHggPSBhbW9zdHJhMSwgc2l6ZSA9IDIwLCByZXBsYWNlID0gVCkNCg0KIyBO428gcG9kZSByZXBldGlyIGFzIG9jb3Jy6m5jaWFzDQpzYW1wbGUoeCA9IGFtb3N0cmEyLCBzaXplID0gMywgIHJlcGxhY2UgPSBGKQ0KYGBgDQoNClBhcmEgZ2FyYW50aXIgcXVlIHNlbXByZSBvIG1lc21vIHJlc3VsdGFkbyBhY29udGXnYSwgcG9kZW1vcyB1dGlsaXphciBhIGZ1bufjbyBzZXQuc2VlZCBjb20gdW0gdmFsb3IgZml4bw0KYGBge3J9DQpzZXQuc2VlZCgxKQ0Kc2FtcGxlKHggPSBhbW9zdHJhMSwgc2l6ZSA9IDIwLCByZXBsYWNlID0gVCkNCmBgYA0KDQoNCg0KIyMjIFNpbXVsYef1ZXMNCg0KTyBSIG5vcyBmb3JuZWNlYSBhbGd1bnMgY29tYW5kb3MgcGFyYSBnZXJhciBkYWRvcyBhbGVhdPNyaW9zLCBzZW5kbyBlbGVzIGRhIGZhbe1saWEgbm9ybWFsLCBiaW5vbWlhbCBlIHVuaWZvcm1lLg0KDQpPcyBjb21hbmRvcyBkYSBmYW1pbGlhIG5vcm1hbCBwb3NzdWVtIG5vcm0gbm8gZmluYWwsIG9zIGJpbm9taWFpcyBwb3NzdWVtIGJpbm9tIGUgYXNzaW0gcG9yIGRpYW50ZS4uLg0KVmVqYSBhYmFpeG8gZXhlbXBsb3M6DQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTgpICNnYXJhbnRpbmRvIHF1ZSBzZW1wcmUgc2FpcuEgbyBtZXNtbyByZXN1bHRhZG8NCg0KIyBzZCByZXByZXNlbnRhIG8gZGVzdmlvIHBhZHLjbyBkb3MgZGFkb3MNCg0KcHJpbnQoInJub3JtIikNCnJub3JtKG49MTAsIG1lYW49MCwgc2Q9MSkNCg0KcHJpbnQoImRub3JtIikNCmRub3JtKHggPSAxOjEwLCBtZWFuID0gMCwgc2QgPSAxKQ0KDQpwcmludCgicG5vcm0iKQ0KcG5vcm0oIHEgPSAxOjEwLCBtZWFuID0gMCwgc2QgPSAxKQ0KDQpwcmludCgicmJpbm9tIikNCnJiaW5vbShzaXplID0gMToxMCwgcHJvYiA9IGMoMC4xLDAuMSwwLjEsMC4xLDAuMSwwLjEsMSwxLDEsMSksIG4gPSAxMCkNCg0KcHJpbnQoImRiaW5vbSIpDQpkYmlub20oc2l6ZSA9IDE6MTAsIHByb2IgPSBjKDAuMSwwLjEsMC4xLDAuMSwwLjEsMC4xLDEsMSwxLDEpLCB4ID0gMToxMCkNCg0KcHJpbnQoInBiaW5vbSIpDQpwYmlub20ocSA9IDE6MTAsIHNpemUgPSAxOjEwLCBwcm9iID0gYygwLjEsMC4xLDAuMSwwLjEsMC4xLDAuMSwxLDEsMSwxKSkNCg0KcHJpbnQoIkRpc3RyaWJ1aefjbyBkZSBwb2lzb24iKQ0KcnBvaXMoMTAwLCA1KQ0KYGBgDQoNCg0KIyMjIFBsb3RzIGLhc2ljbw0KDQpQYXJhIGZhemVyIHBsb3RzLCBvdSBncuFmaWNvcyBlbSBSIHBvZGVtb3MgdXRpbGl6YXIgYSBmdW7n428gcGxvdCgpDQpgYGB7cn0NCnBsb3QoeCA9IGNhcnMkc3BlZWQsIHkgPSBjYXJzJGRpc3QsIHR5cGUgPSAicCIsIHhsYWIgPSAiVmVsb2NpZGFkZSIsIHlsYWIgPSAiRGlzdOJuY2lhIiwgbWFpbiA9ICJEaXN04m5jaWEgeCBWZWxvY2lkYWRlIikNCnBsb3QoeCA9IGNhcnMkc3BlZWQsIHkgPSBjYXJzJGRpc3QsIHR5cGUgPSAibCIsIHhsYWIgPSAiVmVsb2NpZGFkZSIsIHlsYWIgPSAiRGlzdOJuY2lhIiwgbWFpbiA9ICJEaXN04m5jaWEgeCBWZWxvY2lkYWRlIikNCnBsb3QoeCA9IGNhcnMkc3BlZWQsIHkgPSBjYXJzJGRpc3QsIHR5cGUgPSAiaCIsIHhsYWIgPSAiVmVsb2NpZGFkZSIsIHlsYWIgPSAiRGlzdOJuY2lhIiwgbWFpbiA9ICJEaXN04m5jaWEgeCBWZWxvY2lkYWRlIikNCmBgYA0KDQojIyMgVXNhbmRvIG91dHJhIGJpYmxpb3RlY2EuLi4NCg0KUG9kZW1vcyB1dGlsaXphciBhIGVxdWHn428gYWJhaXhvIHBhcmEgcGxvdGFyIHVtIGdy4WZpY28gbGluZWFyDQokeSA9IFxiZXRhXzAgKyBcYmV0YV8xICsgXGVwc2lsb24kDQoNCk9uZGUNCg0KJFxiZXRhXzAgPSAwLDUkDQoNCiRcYmV0YV8xID0gMiwwJA0KDQokeFxzaW0gTigwOzGyKSQNCg0KJFxlcHNpbG9uXHNpbSBOKDA7MrIpJA0KDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCdwbG90bHknKQ0KbGlicmFyeShwbG90bHkpDQoNCnNldC5zZWVkKDUpDQp4ID0gcm5vcm0obj0zNTAsIG1lYW49MCwgc2Q9MSkNCmUgPSBybm9ybShuPTM1MCwgbWVhbj0wLCBzZD0yKQ0KeT0wLjUgKyAyKnggKyBlDQoNCnBsb3QoeD14LCB5PXkpDQoNCnBsb3RfbHkoeD14LCB5PXksIHR5cGU9InNjYXR0ZXIiLCBtb2RlPSJtYXJrZXJzIikNCmBgYA0KDQoNCg0KIyMjIEJhaXhhbmRvIGRhZG9zIGV4dGVybm9zDQoNCkNvbSBhIGZ1bufjbyBkb3dubG9hZCBmaWxlIHBvZGVtb3MgYmFpeGFyIGFycXVpdm9zIGRhIHdlYiwgbmVzdGUgY2FzbyBlbGUgc2VtcHJlIHRyYXRhIGNvbW8gdGV4dG8gb3MgZGFkb3MuDQoNCg0KYGBge3J9DQoNCmJhaXhhciA8LSBmdW5jdGlvbih1cmwpIHsNCiAgDQogICNDcmlhIGEgcGFzdGEgY2FzbyBu428gZXhpc3RhDQogIA0KICBpZighZmlsZS5leGlzdHMoJ2RhdGEnKSl7DQogICAgZGlyLmNyZWF0ZSgnZGF0YScpDQogIH0NCiAgDQogIGZpbGUudXJsID0gdXJsDQogIGZpbGUubG9jYWwgPSBmaWxlLnBhdGgoJy4vZGF0YScsIGJhc2VuYW1lKGZpbGUudXJsKSkNCiAgZG93bmxvYWQuZmlsZSh1cmwgPSBmaWxlLnVybCwgZGVzdGZpbGUgPSBmaWxlLmxvY2FsICwgbW9kZT0nd2InKQ0KfQ0KDQpiYWl4YXIoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9lbHRob25mL2ZpYXAtbWJhLXIvbWFzdGVyL2RhdGEvQ29wYXMuY3N2JykNCmJhaXhhcignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2VsdGhvbmYvZmlhcC1tYmEtci9tYXN0ZXIvZGF0YS9Db3Bhcy1QYXJ0aWRhcy5jc3YnKQ0KYmFpeGFyKCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZWx0aG9uZi9maWFwLW1iYS1yL21hc3Rlci9kYXRhL0NvcGFzLUpvZ2Fkb3Jlcy5jc3YnKQ0KYmFpeGFyKCdodHRwczovL2dpdGh1Yi5jb20vZWx0aG9uZi9maWFwLW1iYS1yL3Jhdy9tYXN0ZXIvZGF0YS9jYW1lcmFzLmJhbHRpbW9yZS54bHN4JykNCg0KYGBgDQoNCiMjIyBMZW5kbyBkYWRvcyBkZSBjc3Yncw0KDQpQYXJhIGxlciBkYWRvcyBkZSBjc3ZzIHBvZGVtb3MgdXRpbGl6YXIgYSBmdW7n428gcmVhZC5jc3YNCg0KDQpgYGB7cn0NCmNvcGFzIDwtIHJlYWQuY3N2KCcuL2RhdGEvQ29wYXMuY3N2JywgaGVhZGVyID0gVCkNCmNvcGFzDQpgYGANCg0KUGFyYSBsZXIgZGFkb3MgZG8gZXhjZWwsIHBvZGVtb3MgdXRpbGl6YXIgbyBwYWNvdGUgDQoNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoJ3JlYWR4bCcpDQpsaWJyYXJ5KHJlYWR4bCkNCg0KZGYuY2FtZXJhcyA8LSByZWFkX3hsc3goJy4vZGF0YS9jYW1lcmFzLmJhbHRpbW9yZS54bHN4JykNCg0KaGVhZChkZi5jYW1lcmFzKQ0KYGBgDQoNCg0KIyMjIE1hbmlwdWxhbmRvIGVzdHJ1dHVyYXMgZGUgdGFiZWxhcyBjb20gZHBseXINCg0KTyBwYWNvdGUgZHBseXIgbm9zIGFqdWRhIGEgbWFuaXB1bGFyIGVzdHJ1dHVyYXMgZGUgdGFiZWxhcyBkZSBtYW5laXJhIGJhc3RhbnRlIGVmaWNpZW50ZS4NCg0KQWJhaXhvIHV0aWxpemFtb3MgbyBwaXBlIHBhcmEgcGFzc2FyIG8gY29udGX6ZG8gDQoNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoJ2RwbHlyJykNCmxpYnJhcnkoZHBseXIpDQoNCkJyRmxpZ2h0czIgJT4lDQptdXRhdGUoUGFydGlkYS5BdHJhc28gPSAoUGFydGlkYS5SZWFsIC0gUGFydGlkYS5QcmV2aXN0YSkpICU+JSANCm11dGF0ZShDaGVnYWRhLkF0cmFzbyA9IChDaGVnYWRhLlJlYWwgLSBDaGVnYWRhLlByZXZpc3RhKSkgJT4lIA0KbXV0YXRlKERpc3RhbmNpYSA9IChzcXJ0KChMYXRPcmlnIC0gTGF0RGVzdCleMiArIChMb25nT3JpZyAtIExvbmdEZXN0KV4yKSkpICU+JSANCm11dGF0ZShUZW1wb1ZpYWdlbS5SZWFsID0gKENoZWdhZGEuUmVhbCAtIFBhcnRpZGEuUmVhbCkpIC0+IHRhYmVsYQ0KDQp0YWJlbGENCmBgYA0KDQoNCg0KDQoNCg0K